package com.zhou.util.tag;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 生成html
 * @author lang.zhou
 * @date   2019-02-01
 * @version v2.0 append(Tag)支持动态修改Tag属性
 */
public class Tag implements Cloneable{
    public static final String SINGLE_DOLT="'";
    public static final String DOUBLE_DOLT="\"";
    public static final String SPACE="&nbsp;";
    public static final String BR="<br>";
    /*** 定义HTML标签的正则表达式*/
    public static final String REGEX_HTML = "<[^>]+>";
    public static Pattern htmlPattern = null;
    /*** false代表有标签体*/
    protected boolean single=false;
    /*** style标签使用的引号*/
    protected String styleDolt;
    /*** 标签名称*/
    protected String name;
    /*** 标签属性*/
    protected Map<String,Two> attributes;
    /*** 标签css*/
    protected Map<String,String> css;
    /*** 标签之前的元素*/
    protected List<Object> beforeElements;
    /*** 标签体内的元素*/
    protected List<Object> body;
    /*** 标签后面的元素*/
    protected List<Object> afterElements;

    public Tag(String name){
        this.name=name;
    }
    public Tag(String name, boolean single){
        this.name=name;
        this.single=single;
    }
    public void setName(String name){
        this.name=name;
    }
    /**
     * 添加一个属性，添加style属性时，和css()不冲突
     * @param name 属性名
     * @param value 属性值，默认使用双引号
     */
    public Tag attr(String name, String value){
        return attr(name,value,DOUBLE_DOLT);
    }
    /**
     * 获得一个属性的值
     * @param name 属性名
     */
    public String attr(String name){
        if(this.attributes != null){
            Two two=this.attributes.get(name);
            return two != null ? two.value : null;
        }
        return null;
    }

    /**
     * @param dolt 有效的值为单引号或双引号，表示这个属性值用哪个引号包裹，如href=""或href=''
     */
    public Tag attr(String name, String value, String dolt){
        if(attributes==null){
            attributes=new HashMap<String,Two>();
        }
        Two t=new Two(value,dolt);
        attributes.put(name,t);
        return this;
    }
    public Tag clazz(String clazz,String dolt){
        return attr("class",clazz,dolt);
    }
    public Tag clazz(String clazz){
        return clazz(clazz,DOUBLE_DOLT);
    }
    /**
     * 添加一个css属性，和attr("style","xxx")不冲突
     * @param name 属性名
     * @param value 属性值
     */
    public Tag css(String name, String value){
        if(css==null){
            css=new HashMap<String,String>();
        }
        css.put(name,value);
        return this;
    }
    protected Tag addBody(Object o, int index){
        if(!single){
            if(body==null){
                body=new ArrayList<Object>();
            }
            if(index==-1){
                body.add(o);
            }else{
                body.add(index,o);
            }
        }
        return this;
    }
    /**
     * 在标签体内(末尾)追加一个元素，和jquery的append一样
     * @param o Tag对象或者字符串
     */
    public Tag append(Object o){
        return addBody(o,-1);
    }
    public Tag appendBr(){
        return addBody(Tag.BR,-1);
    }
    /**
     * 在标签体内(开头)追加一个元素，和jquery的prepend一样
     * @param o Tag对象或者字符串
     */
    public Tag prepend(Object o){
        return addBody(o,0);
    }
    /**
     * 在标签后面追加一个元素，和jquery的after一样
     * @param o Tag对象或者字符串
     */
    public Tag after(Object o){
        if(afterElements==null){
            afterElements=new ArrayList<Object>();
        }
        afterElements.add(o);
        return this;
    }
    /**
     * 在标签前面追加一个元素，和jquery的before一样
     * @param o Tag对象或者字符串
     */
    public Tag before(Object o){
        if(beforeElements==null){
            beforeElements=new ArrayList<Object>();
        }
        beforeElements.add(o);
        return this;
    }
    public boolean is(String name){
        return this.name != null && Objects.equals(this.name,name);
    }
    /**
     * 将标签转换为字符串
     * @return 标签的字符串
     */
    public String html(){
        if(name == null || "".equals(name)){
            return null;
        }
        StringBuilder s=new StringBuilder();
        if(beforeElements!=null && beforeElements.size()>0){
            for(Object e : beforeElements){
                s.append(e);
            }
        }
        s.append("<").append(name);
        String[] styles;
        if(attributes!=null && !attributes.isEmpty()){
            Two t=attributes.get("style");
            if(t!=null){
                styles=t.value.split(";");
                styleDolt=t.dolt;
                if(styles.length>0){
                    if(css==null){
                        css=new HashMap<String,String>();
                    }
                    for (String style : styles) {
                        if (style.contains(":") && style.split(":").length > 1) {
                            css.put(style.split(":")[0], style.split(":")[1]);
                        }
                    }
                }
            }
            for (Map.Entry<String, Two> entry : attributes.entrySet()) {
                if (!"style".equals(entry.getKey())) {
                    String value = entry.getValue().value;
                    s.append(" ").append(entry.getKey()).append("=").append(entry.getValue().dolt)
                            .append(value).append(entry.getValue().dolt);
                }
            }
        }
        if(css!=null && !css.isEmpty()){
            boolean haveStyle=false;
            for(String v : css.values()){
                if(v!=null && !"".equals(v)){
                    haveStyle=true;
                    break;
                }
            }
            if(haveStyle){
                if(styleDolt==null){
                    styleDolt=DOUBLE_DOLT;
                }
                s.append(" style=").append(styleDolt);
                for(Map.Entry<String,String> entry : css.entrySet()){
                    if(entry.getValue()!=null && !"".equals(entry.getValue())){
                        s.append(entry.getKey()).append(":").append(entry.getValue()).append(";");
                    }
                }
                s.append(styleDolt);
            }
        }
        if(!single){
            s.append(">");
            if(body!=null && body.size()>0){
                for(Object e : body){
                    s.append(e);
                }
            }
            s.append("</").append(name).append(">");
        }else{
            s.append("/>");
        }
        if(afterElements!=null && afterElements.size()>0){
            for(Object e : afterElements){
                s.append(e);
            }
        }
        return s.toString();
    }
    public Tag width(String wid){
        return css("width",wid);
    }
    public Tag height(String hi){
        return css("height",hi);
    }
    public Tag onClick(String func){
        return onClick(func,DOUBLE_DOLT);
    }
    public Tag onClick(String func, String dolt){
        return attr("onclick",func,dolt);
    }

    public Tag onChange(String func){
        return onChange(func,DOUBLE_DOLT);
    }
    public Tag onChange(String func, String dolt){
        return attr("onchange",func,dolt);
    }

    public Tag onInput(String func){
        return onInput(func,DOUBLE_DOLT);
    }
    public Tag onInput(String func, String dolt){
        return attr("oninput",func,dolt);
    }

    public Tag val(String value){
        return val(value,DOUBLE_DOLT);
    }
    public Tag val(String value, String dolt){
        return attr("value",value,dolt);
    }

    public Tag href(String href){
        return href(href,DOUBLE_DOLT);
    }
    public Tag href(String href, String dolt){
        if(this.is("a")){
            return attr("href",href,dolt);
        }
        return this;
    }
    public Tag cancleHref(){
        if(this.is("a")){
            return href("javascript:void(0);");
        }
        return this;
    }

    public Tag src(String src){
        return src(src,DOUBLE_DOLT);
    }
    public Tag src(String src, String dolt){
        return attr("src",src,dolt);
    }

    public Tag title(String title){
        return title(title,DOUBLE_DOLT);
    }
    public Tag title(String title, String dolt){
        return attr("title",title,dolt);
    }

    public Tag color(String color){
        return css("color",color);
    }

    public Tag style(String style){
        return style(style,DOUBLE_DOLT);
    }
    public Tag style(String style, String dolt){
        return attr("style",style,dolt);
    }

    public Tag id(String id){
        return attr("id",id);
    }
    public Tag name(String name){
        return attr("name",name);
    }

    public Tag text(String text){
        if(body!=null){
            body.clear();
        }
        return append(text);
    }
    public String text(){
        if(body!=null){
            return this.html().replaceAll(REGEX_HTML,"");
        }
        return null;
    }
    public void empty(){
        if(this.body!= null){
            this.body.clear();
        }
        if(this.attributes!= null){
            this.attributes.clear();
        }
        if(this.css!= null){
            this.css.clear();
        }
        if(this.beforeElements!= null){
            this.beforeElements.clear();
        }
        if(this.afterElements!= null){
            this.afterElements.clear();
        }
    }

    public List<Object> children(){
        List<Object> tagList = new ArrayList<Object>();
        for(Object key : this.body){
            if(key != null){
                tagList.add(key);
            }
        }
        return tagList;
    }
    public static String getSpace(int n){
        StringBuilder s=new StringBuilder();
        for(int i=0;i<n;i++){
            s.append(SPACE);
        }
        return s.toString();
    }
    /*public static void main(String[] args){
        com.zhou.util.common.Tag div=new com.zhou.util.common.Tag("div").style("background:#ffffff");
        com.zhou.util.common.Tag t = new com.zhou.util.common.Tag("a").cancleHref().append("click me!");
        div.append(t).append("asd").title("measd");
        t.title("after insert title");
        //Tag2 a= Tag2.fromHtml(div.toString());

        System.out.println();

    }*/
    @Override
    public String toString(){
        return this.html();
    }
    protected class Two{
        private String value;
        private String dolt;
        private Two(String value,String dolt){
            this.value=value;
            this.dolt=dolt;
        }
    }
    public static String toText(String str){
        if(htmlPattern == null){
            htmlPattern = Pattern.compile(REGEX_HTML);
        }
        return str == null || str.length() ==0 ? "" : htmlPattern.matcher(str).replaceAll("");
    }
    @Override
    public Tag clone(){
        try {
            return (Tag) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            throw new RuntimeException("克隆对象失败！");
        }
    }
}
